home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
lang
/
rcs567pc
/
diff16
/
dir.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-25
|
10KB
|
391 lines
/* Read, sort and compare two directories. Used for GNU DIFF.
Copyright (C) 1988, 1989 Free Software Foundation, Inc.
Modified for DOS and OS/2 on 1991/09/14 by Kai Uwe Rommel
<rommel@ars.muc.de>.
This file is part of GNU DIFF.
GNU DIFF is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU DIFF is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU DIFF; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "diff.h"
static int compare_names ();
/* Read the directory named DIRNAME and return a sorted vector
of filenames for its contents. NONEX nonzero means this directory is
known to be nonexistent, so return zero files. */
struct dirdata
{
int length; /* # elements in `files' */
char **files; /* Sorted names of files in the dir */
};
#if defined(MSDOS)
/*
** due to difference of opinion btw gnu and microsoft about what
** const means, const is defined away in diff.h, which causes warnings
** when compiling the headers. This ugliness is avoided here.
*/
#ifdef const
#undef const
#endif
#include <string.h>
#include <ctype.h>
#ifdef OS2
#define strcmp stricmp
/* stricmp() this is important for the HPFS because it is
/* case-preserving but NOT case-sensitive */
#include <stdlib.h>
#define INCL_NOPM
#include <os2.h>
#define _A_NORMAL 0x00
#define _A_SUBDIR 0x10
#define _MAX_NAME 256
#else
#ifdef __TURBOC__
#include <dir.h>
#define _A_NORMAL 0x00
#define _A_SUBDIR 0x10
#endif
#include <dos.h>
#define _MAX_NAME 13
#endif
struct direct {
char d_name[_MAX_NAME];
};
typedef struct _dir {
int first;
#ifdef OS2
FILEFINDBUF find;
#else
#ifdef __TURBOC__
struct ffblk dta;
#else
struct find_t dta;
#endif
#endif
struct direct current;
} DIR;
#ifdef OS2
static HDIR hdir;
static USHORT count;
static BOOL lower;
#endif
#ifdef OS2
int IsFileSystemFAT(char *dir)
{
USHORT nDrive;
ULONG lMap;
BYTE bData[64], bName[3];
USHORT cbData;
if ( _osmode == DOS_MODE )
return TRUE;
else
{
/* We separate FAT and HPFS file systems here.
* Filenames read from a FAT system are converted to lower case
* while the case of filenames read from a HPFS (and other future
* file systems, like Unix-compatibles) is preserved.
*/
if ( isalpha(dir[0]) && (dir[1] == ':') )
nDrive = toupper(dir[0]) - '@';
else
DosQCurDisk(&nDrive, &lMap);
bName[0] = (char) (nDrive + '@');
bName[1] = ':';
bName[2] = 0;
cbData = sizeof(bData);
if ( !DosQFSAttach(bName, 0U, 1U, bData, &cbData, 0L) )
return !strcmp(bData + (*(USHORT *) (bData + 2) + 7), "FAT");
else
return FALSE;
/* End of this ugly code */
}
}
#endif
DIR *
opendir(char *name) {
char localname[_MAX_NAME];
DIR *rval = malloc(sizeof(DIR));
strcpy(localname,name);
strcat(localname,"/*.*");
#ifdef OS2
lower = IsFileSystemFAT(name);
hdir = count = 1;
#endif
if(rval == NULL ||
#ifdef OS2
DosFindFirst(localname, &hdir, _A_NORMAL|_A_SUBDIR, &rval->find,
sizeof(FILEFINDBUF), &count, 0L) != 0)
#else
#ifdef __TURBOC__
findfirst(localname,&rval->dta,_A_NORMAL|_A_SUBDIR) != 0)
#else
_dos_findfirst(localname,_A_NORMAL|_A_SUBDIR,&rval->dta) != 0)
#endif
#endif
return NULL;
rval->first = 1;
return rval;
}
void
closedir(DIR *x) {
free(x);
}
struct direct *
readdir(DIR *thisdir) {
/*
** first time through, we don't need to look for a file
*/
if(!thisdir->first) {
#ifdef OS2
if(DosFindNext(hdir, &thisdir->find, sizeof(FILEFINDBUF),
&count) != 0)
#else
#ifdef __TURBOC__
if(findnext(&thisdir->dta) != 0)
#else
if(_dos_findnext(&thisdir->dta) != 0)
#endif
#endif
return NULL;
} else
thisdir->first = 0;
#ifdef OS2
strcpy(thisdir->current.d_name,thisdir->find.achName);
#else
#ifdef __BORLANDC__
strcpy(thisdir->current.d_name,thisdir->dta.ff_name);
#else
strcpy(thisdir->current.d_name,thisdir->dta.name);
#endif
#endif
/* thisdir->current.d_name[13] = '\0'; */
#ifdef OS2
if ( lower )
#endif
strlwr(thisdir->current.d_name);
return &thisdir->current;
}
#endif /* MSDOS */
static struct dirdata
dir_sort (dirname, nonex)
char *dirname;
int nonex;
{
register DIR *reading;
register struct direct *next;
struct dirdata dirdata;
/* Address of block containing the files that are described. */
char **files;
/* Length of block that `files' points to, measured in files. */
int nfiles;
/* Index of first unused in `files'. */
int files_index;
if (nonex)
{
dirdata.length = 0;
dirdata.files = 0;
return dirdata;
}
/* Open the directory and check for errors. */
reading = opendir (dirname);
if (!reading)
{
perror_with_name (dirname);
dirdata.length = -1;
return dirdata;
}
/* Initialize the table of filenames. */
nfiles = 100;
files = (char **) xmalloc (nfiles * sizeof (char *));
files_index = 0;
/* Read the directory entries, and insert the subfiles
into the `files' table. */
while (next = readdir (reading))
{
/* Ignore the files `.' and `..' */
if (next->d_name[0] == '.'
&& (next->d_name[1] == 0
|| (next->d_name[1] == '.'
&& next->d_name[2] == 0)))
continue;
if (files_index == nfiles)
{
nfiles *= 2;
files
= (char **) xrealloc (files, sizeof (char *) * nfiles);
}
files[files_index++] = concat (next->d_name, "", "");
}
closedir (reading);
/* Sort the table. */
qsort (files, files_index, sizeof (char *), compare_names);
/* Return a description of location and length of the table. */
dirdata.files = files;
dirdata.length = files_index;
return dirdata;
}
/* Sort the files now in the table. */
static int
compare_names (file1, file2)
char **file1, **file2;
{
return strcmp (*file1, *file2);
}
/* Compare the contents of two directories named NAME1 and NAME2.
This is a top-level routine; it does everything necessary for diff
on two directories.
NONEX1 nonzero says directory NAME1 doesn't exist, but pretend it is
empty. Likewise NONEX2.
HANDLE_FILE is a caller-provided subroutine called to handle each file.
It gets five operands: dir and name (rel to original working dir) of file
in dir 1, dir and name pathname of file in dir 2, and the recursion depth.
For a file that appears in only one of the dirs, one of the name-args
to HANDLE_FILE is zero.
DEPTH is the current depth in recursion.
Returns the maximum of all the values returned by HANDLE_FILE,
or 2 if trouble is encountered in opening files. */
int
diff_dirs (name1, name2, handle_file, depth, nonex1, nonex2)
char *name1, *name2;
#if !defined(MSDOS)
int (*handle_file) ();
#else
/* sorry, rms, I can't live with the assumption that
** sizeof(char *) == sizeof(int)
*/
int (*handle_file)(char *,char *,
char *,char *,int);
#endif
int depth, nonex1, nonex2;
{
struct dirdata data1, data2;
register int i1, i2;
int val = 0;
int v1;
/* Get sorted contents of both dirs. */
data1 = dir_sort (name1, nonex1);
data2 = dir_sort (name2, nonex2);
if (data1.length == -1 || data2.length == -1)
{
if (data1.length >= 0)
free (data1.files);
if (data2.length >= 0)
free (data2.files);
return 2;
}
i1 = 0;
i2 = 0;
/* If -Sname was specified, and this is the topmost level of comparison,
ignore all file names less than the specified starting name. */
if (dir_start_file && depth == 0)
{
while (i1 < data1.length && strcmp (data1.files[i1], dir_start_file) < 0)
i1++;
while (i2 < data2.length && strcmp (data2.files[i2], dir_start_file) < 0)
i2++;
}
/* Loop while files remain in one or both dirs. */
while (i1 < data1.length || i2 < data2.length)
{
int nameorder;
/* Compare next name in dir 1 with next name in dir 2.
At the end of a dir,
pretend the "next name" in that dir is very large. */
if (i1 == data1.length)
nameorder = 1;
else if (i2 == data2.length)
nameorder = -1;
else
nameorder = strcmp (data1.files[i1], data2.files[i2]);
if (nameorder == 0)
{
/* We have found a file (or subdir) in common between both dirs.
Compare the two files. */
v1 = (*handle_file) (name1, data1.files[i1], name2, data2.files[i2],
depth + 1);
i1++, i2++;
}
if (nameorder < 0)
{
/* Next filename in dir 1 is less; that is a file in dir 1 only. */
v1 = (*handle_file) (name1, data1.files[i1], name2, 0, depth + 1);
i1++;
}
if (nameorder > 0)
{
/* Next filename in dir 2 is less; that is a file in dir 2 only. */
v1 = (*handle_file) (name1, 0, name2, data2.files[i2], depth + 1);
i2++;
}
if (v1 > val)
val = v1;
}
if (data1.files)
free (data1.files);
if (data2.files)
free (data2.files);
return val;
}